package org.toobsframework.pres.chart; import java.awt.Color; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import org.apache.commons.jxpath.JXPathContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.AxisLocation; import org.jfree.chart.axis.CategoryAxis; import org.jfree.chart.axis.CategoryAxis3D; import org.jfree.chart.axis.CategoryLabelPositions; import org.jfree.chart.labels.ItemLabelAnchor; import org.jfree.chart.labels.ItemLabelPosition; import org.jfree.chart.labels.StandardCategoryItemLabelGenerator; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.Plot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.renderer.AbstractRenderer; import org.jfree.chart.renderer.category.AreaRenderer; import org.jfree.chart.renderer.category.BarRenderer; import org.jfree.chart.renderer.category.BarRenderer3D; import org.jfree.chart.renderer.category.CategoryItemRenderer; import org.jfree.chart.renderer.category.EvenOddBarRenderer; import org.jfree.chart.renderer.category.EvenOddBarRenderer3D; import org.jfree.chart.renderer.category.EvenOddStackedBarRenderer; import org.jfree.chart.renderer.category.EvenOddStackedBarRenderer3D; import org.jfree.chart.renderer.category.LineAndShapeRenderer; import org.jfree.chart.renderer.category.StackedAreaRenderer; import org.jfree.chart.renderer.category.StackedBarRenderer; import org.jfree.chart.renderer.category.StackedBarRenderer3D; import org.jfree.ui.RectangleEdge; import org.jfree.ui.RectangleInsets; import org.jfree.ui.TextAnchor; import org.jfree.ui.VerticalAlignment; import org.jfree.util.SortOrder; import org.toobsframework.pres.chart.config.BasePlot; import org.toobsframework.pres.chart.config.DataElement; import org.toobsframework.pres.chart.config.Dataset; import org.toobsframework.pres.chart.config.DatasetGroup; import org.toobsframework.pres.chart.config.DatasetSeries; import org.toobsframework.pres.chart.config.DomainAxisDef; import org.toobsframework.pres.chart.config.Legend; import org.toobsframework.pres.chart.config.RangeAxisDef; import org.toobsframework.pres.chart.config.RectangleSet; import org.toobsframework.pres.chart.config.TextLabel; import org.toobsframework.pres.chart.config.types.SubtitlePositionType; import org.toobsframework.pres.chart.config.types.SubtitleVerticalAlignmentType; import org.toobsframework.data.beanutil.BeanMonkey; import org.toobsframework.pres.util.ParameterUtil; //@SuppressWarnings("unchecked") public class ChartUtil { private static Log log = LogFactory.getLog(ChartUtil.class); public static final int RENDERER_TYPE_AREA = 0; public static final int RENDERER_TYPE_BAR = 1; public static final int RENDERER_TYPE_LINE = 2; public static final int RENDERER_TYPE_PIE = 3; public static final int RENDERER_TYPE_BAR_EVEN_ODD = 4; public static final int PLOT_CATEGORY_TYPE = 0; public static final int PLOT_XY_TYPE = 1; public static final int PLOT_COMBINEDDOMAINCATEGORY_TYPE = 2; public static final int PLOT_COMBINEDRANGECATEGORY_TYPE = 3; public static final int PLOT_MULTICATEGORY_TYPE = 4; public static final int PLOT_SPIDER_TYPE = 5; public static final int DOM_LABEL_STANDARD_TYPE = 0; public static final int DOM_LABEL_UP_45_TYPE = 1; public static final int DOM_LABEL_DOWN_45_TYPE = 2; public static final int DOM_LABEL_UP_90_TYPE = 3; public static final int DOM_LABEL_DOWN_90_TYPE = 4; private static Map<String, Integer> supportedPlots; static { supportedPlots = new HashMap<String, Integer>(); supportedPlots.put("category", PLOT_CATEGORY_TYPE ); supportedPlots.put("xy", PLOT_XY_TYPE ); supportedPlots.put("combinedDomainCategory", PLOT_COMBINEDDOMAINCATEGORY_TYPE ); supportedPlots.put("combinedRangeCategory", PLOT_COMBINEDRANGECATEGORY_TYPE ); supportedPlots.put("multiCategory", PLOT_MULTICATEGORY_TYPE ); supportedPlots.put("spider", PLOT_SPIDER_TYPE ); } private static Map<String, Integer> supportedRenderers; static { supportedRenderers = new HashMap<String, Integer>(); supportedRenderers.put("area", RENDERER_TYPE_AREA ); supportedRenderers.put("bar", RENDERER_TYPE_BAR ); supportedRenderers.put("barEvenOdd", RENDERER_TYPE_BAR_EVEN_ODD ); supportedRenderers.put("lineAndShape", RENDERER_TYPE_LINE ); supportedRenderers.put("pie", RENDERER_TYPE_PIE ); } private static Map<String, AxisLocation> axisLocations; static { axisLocations = new HashMap<String, AxisLocation>(); axisLocations.put("bottomOrLeft", AxisLocation.BOTTOM_OR_LEFT ); axisLocations.put("bottomOrRight", AxisLocation.BOTTOM_OR_RIGHT ); axisLocations.put("topOrLeft", AxisLocation.TOP_OR_LEFT ); axisLocations.put("topOrRight", AxisLocation.TOP_OR_RIGHT ); } private static Map<String, Integer> domainLabelPositions; static { domainLabelPositions = new HashMap<String, Integer>(); domainLabelPositions.put("standard", DOM_LABEL_STANDARD_TYPE ); domainLabelPositions.put("up45", DOM_LABEL_UP_45_TYPE ); domainLabelPositions.put("down45", DOM_LABEL_DOWN_45_TYPE ); domainLabelPositions.put("up90", DOM_LABEL_UP_90_TYPE ); domainLabelPositions.put("down90", DOM_LABEL_DOWN_90_TYPE ); } public static void configureLegend(JFreeChart chart, Legend legend, Map params) { if (legend != null) { if (legend.getBorder() != null) { RectangleInsets rect = getRectangle(legend.getBorder(), params); chart.getLegend().setBorder(rect.getTop(), rect.getLeft(), rect.getBottom(), rect.getRight()); } if (legend.getPadding() != null) { chart.getLegend().setItemLabelPadding(getRectangle(legend.getPadding(), params)); } } } public static VerticalAlignment getVerticalAlignment(SubtitleVerticalAlignmentType verticalAlignment) { VerticalAlignment valign = null; switch (verticalAlignment.getType()) { case SubtitleVerticalAlignmentType.TOP_TYPE: valign = VerticalAlignment.TOP; break; case SubtitleVerticalAlignmentType.BOTTOM_TYPE: valign = VerticalAlignment.BOTTOM; break; case SubtitleVerticalAlignmentType.CENTER_TYPE: valign = VerticalAlignment.CENTER; break; } return valign; } public static RectangleEdge getPosition(SubtitlePositionType position) { RectangleEdge edge = null; switch (position.getType()) { case SubtitlePositionType.TOP_TYPE: edge = RectangleEdge.TOP; break; case SubtitlePositionType.BOTTOM_TYPE: edge = RectangleEdge.BOTTOM; break; case SubtitlePositionType.LEFT_TYPE: edge = RectangleEdge.LEFT; break; case SubtitlePositionType.RIGHT_TYPE: edge = RectangleEdge.RIGHT; break; } return edge; } public static String evaluateTextLabel(TextLabel textLabel, Map params) { if (textLabel == null || textLabel.getPath() == null) return null; if (textLabel.getIsStatic()) { return ParameterUtil.resolveParam(textLabel.getPath(), params, textLabel.getDefault())[0]; } JXPathContext context = JXPathContext.newContext(params); String labelText = (String)context.getValue(textLabel.getPath()); if (labelText == null & textLabel.getDefault() != null) { labelText = textLabel.getDefault(); } return labelText; } public static java.awt.Font getFont(TextLabel textLabel, java.awt.Font defaultFont) { if (textLabel != null && textLabel.getFont() != null) { return new java.awt.Font( textLabel.getFont().getName(), textLabel.getFont().getStyle().getType(), textLabel.getFont().getSize()); } else { return defaultFont; } } public static Color getColor(String color) { return new Color(Integer.parseInt(color, 16)); } public static RectangleInsets getRectangle(RectangleSet rectangleSet, Map params) { double top = Double.parseDouble( ParameterUtil.resolveParam(rectangleSet.getTop(), params, "0.0")[0] ); double bot = Double.parseDouble( ParameterUtil.resolveParam(rectangleSet.getBottom(), params, "0.0")[0] ); double lef = Double.parseDouble( ParameterUtil.resolveParam(rectangleSet.getLeft(), params, "0.0")[0] ); double rit = Double.parseDouble( ParameterUtil.resolveParam(rectangleSet.getRight(), params, "0.0")[0] ); return new RectangleInsets(top, lef, bot, rit); } public static Object getDatasetValue(Object datasetRow, DataElement dataElement, Object defaultValue) throws ChartException { try { if (dataElement != null && dataElement.getIsStatic()) { return dataElement.getPath(); } else if (dataElement != null) { Object value = null; value = BeanMonkey.getPropertyValue(datasetRow, dataElement.getPath()); if (value == null) { value = defaultValue; } return value; } else { return defaultValue; } } catch (IllegalAccessException e) { log.error("Chart data search exception " + e.getMessage(), e); throw new ChartException(e); } catch (InvocationTargetException e) { log.error("Chart data search exception " + e.getMessage(), e); throw new ChartException(e); } catch (NoSuchMethodException e) { log.error("Chart data search exception " + e.getMessage(), e); throw new ChartException(e); } } public static CategoryAxis createCategoryAxis(DomainAxisDef categoryAxisDef, Map params, boolean is3D) { CategoryAxis categoryAxis; if (is3D) { categoryAxis = new CategoryAxis3D(); } else { categoryAxis = new CategoryAxis(); } if (categoryAxisDef != null) { if (categoryAxisDef.getDomainLabel() != null) { categoryAxis.setLabel(evaluateTextLabel(categoryAxisDef.getDomainLabel(), params)); if (categoryAxisDef.getDomainLabel().getFont() != null) { categoryAxis.setLabelFont(getFont(categoryAxisDef.getDomainLabel(), null)); } categoryAxis.setLabelPaint(getColor(categoryAxisDef.getDomainLabel().getColor())); } if (categoryAxisDef.getLabelPosition() != null) { Integer labelPos = domainLabelPositions.get(ParameterUtil.resolveParam(categoryAxisDef.getLabelPosition(), params, "standard")[0]); if (labelPos != null) { switch (labelPos) { case DOM_LABEL_STANDARD_TYPE: categoryAxis.setCategoryLabelPositions(CategoryLabelPositions.STANDARD); break; case DOM_LABEL_UP_45_TYPE: categoryAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45); break; case DOM_LABEL_DOWN_45_TYPE: categoryAxis.setCategoryLabelPositions(CategoryLabelPositions.DOWN_45); break; case DOM_LABEL_UP_90_TYPE: categoryAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90); break; case DOM_LABEL_DOWN_90_TYPE: categoryAxis.setCategoryLabelPositions(CategoryLabelPositions.DOWN_90); break; } } } double domainMargin = Double.parseDouble( ParameterUtil.resolveParam(categoryAxisDef.getDomainMargin(), params, "0.0")[0] ); double lowerMargin = Double.parseDouble( ParameterUtil.resolveParam(categoryAxisDef.getLowerMargin(), params, "0.0")[0] ); double upperMargin = Double.parseDouble( ParameterUtil.resolveParam(categoryAxisDef.getUpperMargin(), params, "0.0")[0] ); categoryAxis.setCategoryMargin(domainMargin); categoryAxis.setLowerMargin(lowerMargin); categoryAxis.setUpperMargin(upperMargin); } return categoryAxis; } public static void configurePlot(Plot plot, org.toobsframework.pres.chart.config.BasePlot plotDef, DomainAxisDef categoryAxisDef, RangeAxisDef valueAxisDef, Map params) { if (plotDef != null) { float foregroundAlpha = Float.parseFloat( ParameterUtil.resolveParam(plotDef.getForegroundAlpha(), params, "1.0")[0] ); plot.setForegroundAlpha(foregroundAlpha); if (plot instanceof CategoryPlot && ParameterUtil.resolveParam(plotDef.getOrientation(), params, "horizontal")[0].equals("horizontal")) { ((CategoryPlot)plot).setOrientation(PlotOrientation.HORIZONTAL); boolean is3D = (ParameterUtil.resolveParam(plotDef.getIs3D(), params, "false")[0].equals("false") ? false : true); if (is3D) { ((CategoryPlot)plot).setRowRenderingOrder(SortOrder.DESCENDING); ((CategoryPlot)plot).setColumnRenderingOrder(SortOrder.DESCENDING); } } else if (plot instanceof CategoryPlot) { ((CategoryPlot)plot).setOrientation(PlotOrientation.VERTICAL); } if (plotDef.getInsets() != null) { plot.setInsets(getRectangle(plotDef.getInsets(), params)); } if (plot instanceof CategoryPlot && plotDef.getAxisOffsets() != null) { ((CategoryPlot)plot).setAxisOffset(getRectangle(plotDef.getAxisOffsets(), params)); } if (plotDef.getBackgroundColor() != null) { plot.setBackgroundPaint(getColor(plotDef.getBackgroundColor())); } if (plot instanceof CategoryPlot && categoryAxisDef != null) { AxisLocation dLabelPos = axisLocations.get(ParameterUtil.resolveParam(categoryAxisDef.getLocation(), params, "bottomOrLeft")[0]); if (dLabelPos != null) { ((CategoryPlot)plot).setDomainAxisLocation(dLabelPos); } ((CategoryPlot)plot).setDomainGridlinesVisible(categoryAxisDef.getShowGridlines()); if (categoryAxisDef.getGridColor() != null) { ((CategoryPlot)plot).setDomainGridlinePaint(getColor(categoryAxisDef.getGridColor())); } } if (plot instanceof CategoryPlot && valueAxisDef != null) { AxisLocation rLabelPos = axisLocations.get(ParameterUtil.resolveParam(valueAxisDef.getLocation(), params, "bottomOrRight")[0]); if (rLabelPos != null) { ((CategoryPlot)plot).setRangeAxisLocation(rLabelPos); } ((CategoryPlot)plot).setRangeGridlinesVisible(valueAxisDef.getShowGridlines()); if (valueAxisDef.getGridColor() != null) { ((CategoryPlot)plot).setRangeGridlinePaint(getColor(valueAxisDef.getGridColor())); } } } } public static AbstractRenderer getRenderer(BasePlot plot, DatasetGroup group, Map params) { AbstractRenderer renderer = null; String format = ParameterUtil.resolveParam(group.getRenderer(), params, "area")[0]; boolean is3D = (ParameterUtil.resolveParam(plot.getIs3D(), params, "false")[0].equals("false") ? false : true); switch (supportedRenderers.get(format)) { case ChartUtil.RENDERER_TYPE_AREA: if (group.getStacked()) { renderer = new StackedAreaRenderer(); if (group.getRenderAsPercentages()) { ((StackedAreaRenderer)renderer).setRenderAsPercentages(true); } } else { renderer = new AreaRenderer(); } break; case ChartUtil.RENDERER_TYPE_BAR: if (is3D) { if (group.getStacked()) { renderer = new StackedBarRenderer3D(); if (group.getRenderAsPercentages()) { ((StackedBarRenderer3D)renderer).setRenderAsPercentages(true); } } else { renderer = new BarRenderer3D(); } } else { if (group.getStacked()) { renderer = new StackedBarRenderer(); if (group.getRenderAsPercentages()) { ((StackedBarRenderer)renderer).setRenderAsPercentages(true); } } else { renderer = new BarRenderer(); } } break; case ChartUtil.RENDERER_TYPE_BAR_EVEN_ODD: if (is3D) { if (group.getStacked()) { renderer = new EvenOddStackedBarRenderer3D(group.getEven()); if (group.getRenderAsPercentages()) { ((EvenOddStackedBarRenderer3D)renderer).setRenderAsPercentages(true); } } else { renderer = new EvenOddBarRenderer3D(group.getEven()); } } else { if (group.getStacked()) { renderer = new EvenOddStackedBarRenderer(group.getEven()); if (group.getRenderAsPercentages()) { ((EvenOddStackedBarRenderer)renderer).setRenderAsPercentages(true); } } else { renderer = new EvenOddBarRenderer(group.getEven()); } } break; case ChartUtil.RENDERER_TYPE_LINE: renderer = new LineAndShapeRenderer(); break; case ChartUtil.RENDERER_TYPE_PIE: break; } configureDomainItemLabels(plot, renderer, params, is3D); configureSeriesPaint(plot, group, renderer); return renderer; } public static void configureDomainItemLabels(BasePlot plot, AbstractRenderer renderer, Map params, boolean is3D) { if (plot.getShowDomainItemLabels()) { String orientation = ParameterUtil.resolveParam(plot.getOrientation(), params, "horizontal")[0]; if (orientation.equals("horizontal")) { ItemLabelPosition position1; if (is3D) { position1 = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE2, TextAnchor.CENTER_LEFT); renderer.setItemLabelAnchorOffset(15.0d); } else { position1 = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE3, TextAnchor.CENTER_LEFT); } renderer.setPositiveItemLabelPosition(position1); ItemLabelPosition position2 = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE9, TextAnchor.CENTER_RIGHT); renderer.setNegativeItemLabelPosition(position2); } else if (orientation.equals("vertical")) { ItemLabelPosition position1; if (is3D) { position1 = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE1, TextAnchor.BOTTOM_CENTER); renderer.setItemLabelAnchorOffset(10.0d); } else { position1 = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BOTTOM_CENTER); } renderer.setPositiveItemLabelPosition(position1); ItemLabelPosition position2 = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE6, TextAnchor.TOP_CENTER); renderer.setNegativeItemLabelPosition(position2); } renderer.setBaseItemLabelsVisible(true); ((CategoryItemRenderer)renderer).setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator()); } } public static void configureSeriesPaint(org.toobsframework.pres.chart.config.BasePlot plotDef, DatasetGroup datasetGroup, AbstractRenderer renderer) { for (int i = 0; i < datasetGroup.getDatasetCount(); i++) { Dataset dataset = datasetGroup.getDataset(i); for (int s = 0; s < dataset.getDatasetSeriesCount(); s++) { DatasetSeries series = dataset.getDatasetSeries(s); if (series.getColor() != null) { renderer.setSeriesPaint(i + s, getColor(series.getColor())); } } } } public static Map<String, Integer> getSupportedPlots() { return supportedPlots; } }